﻿using System;
using System.ComponentModel;
using System.Diagnostics;
using System.Linq;
using Microsoft.SharePoint;
using Microsoft.SharePoint.Workflow;

namespace Smart.Common
{
	[Localizable(false)]
	[DebuggerStepThrough]
	public static class SPListExts
	{
		/// <summary>
		/// Returns field id, loaded from <paramref name="list"/> by <paramref name="titleOrName"/>
		/// </summary>
		public static Guid GetFieldId(this SPList list, string titleOrName)
		{
			var field = GetField(list, titleOrName);

			return (field == null ? Guid.Empty : field.Id);
		}

		/// <summary>
		/// Returns field type, loaded from <paramref name="list"/> by <paramref name="titleOrName"/>
		/// </summary>
		public static SPFieldType GetFieldType(this SPList list, string titleOrName)
		{
			var field = GetField(list, titleOrName);

			return (field == null ? SPFieldType.Text : field.Type);
		}

		/// <summary>
		/// Returns field internal name, loaded from <paramref name="list"/> by <paramref name="titleOrName"/>
		/// </summary>
		public static string GetFieldName(this SPList list, string titleOrName)
		{
			var field = GetField(list, titleOrName);

			return (field != null ? field.InternalName : null);
		}

		/// <summary>
		/// Returns field, loaded from <paramref name="list"/> by <paramref name="fieldId"/>
		/// </summary>
		public static SPField GetField(this SPList list, Guid fieldId)
		{
			if (list == null || fieldId.IsEmpty())
				return null;

			try
			{
				return list.Fields[fieldId];
			}
			catch (Exception x)
			{
				H.LX("SPListExts.GetField", "GetField fieldId: " + fieldId, x);
				return null;
			}
		}

		/// <summary>
		/// Returns field, loaded from <paramref name="list"/> by <paramref name="titleOrName"/>
		/// </summary>
		public static SPField GetField(this SPList list, string titleOrName)
		{
			if (list == null || titleOrName.IsNullOrEmpty())
				return null;

			try
			{
				// This method searches by (1) InternalName, (2) DisplayName, {3} StaticName
				return list.Fields.GetField(titleOrName);
			}
			catch (Exception x)
			{
				H.LX("SPListExts.GetField", "GetField titleOrName: " + titleOrName, x);
				return null;
			}
		}

		/// <summary>
		/// Loads item from list by <paramref name="id"/>
		/// </summary>
		public static SPListItem GetItem(this SPList list, int id)
		{
			SPListItem item = null;

			try
			{
				if (list != null && id > 0) item = list.GetItemById(id);
			}
			catch (Exception x)
			{
				H.LT(String.Concat("SPListExts.GetItem (", (list == null ? "null" : list.Title), ", ", id, ").{0}: {1}"), x.GetType().Name, x.Message);
			}

			return item;
		}

		/// <summary>
		/// Loads item from list by <paramref name="lookupValue"/>
		/// </summary>
		public static SPListItem GetItem(this SPList list, string lookupValue)
		{
			int id;
			string name;

			SPH.DispatchLookupValue(lookupValue, out id, out name);

			return GetItem(list, id);
		}

		/// <summary>
		/// Returns field <paramref name="fieldName"/> value in item, loaded from <paramref name="list"/> by <paramref name="id"/>
		/// </summary>
		public static object GetItemValue(this SPList list, int id, string fieldName)
		{
			return GetItem(list, id).Get(fieldName);
		}

		/// <summary>
		/// Returns field <paramref name="fieldId"/> value in item, loaded from <paramref name="list"/> by <paramref name="id"/>
		/// </summary>
		public static object GetItemValue(this SPList list, int id, Guid fieldId)
		{
			return GetItem(list, id).Get(fieldId);
		}

		/// <summary>
		/// Returns field <paramref name="fieldName"/> value in item, loaded from <paramref name="list"/> by <paramref name="lookupValue"/>
		/// </summary>
		public static object GetItemValue(this SPList list, string lookupValue, string fieldName)
		{
			return GetItem(list, lookupValue).Get(fieldName);
		}

		/// <summary>
		/// Returns field <paramref name="fieldId"/> value in item, loaded from <paramref name="list"/> by <paramref name="lookupValue"/>
		/// </summary>
		public static object GetItemValue(this SPList list, string lookupValue, Guid fieldId)
		{
			return GetItem(list, lookupValue).Get(fieldId);
		}

		/// <summary>
		/// Return Web relative list Url
		/// </summary>
		public static string GetUrl(this SPList list)
		{
			return list == null ? null : list.RootFolder.Url;
		}

		/// <summary>
		/// Return full list Url
		/// </summary>
		public static string GetFullUrl(this SPList list)
		{
			return list == null ? null : list.RootFolder.GetFullUrl();
		}

		/// <summary>
		/// Return Server relative list Url
		/// </summary>
		public static string GetServerRelativeUrl(this SPList list)
		{
			return list == null ? null : list.RootFolder.ServerRelativeUrl;
		}

		/// <summary>
		/// Checks whether list is system
		/// </summary>
		public static bool IsSystem(this SPList list)
		{
			return list.Hidden || list.GetUrl().StartsWith("_");
		}

		/// <summary>
		/// Return list Name
		/// </summary>
		public static string GetName(this SPList list)
		{
			return list.RootFolder.Name;
		}

		/// <summary>
		/// Executes <paramref name="method"/> for each <paramref name="list"/> workflow association
		/// </summary>
		/// <exception cref="ArgumentNullException"><paramref name="method"/> is null</exception>
		public static void ForEachAssociation(this SPList list, Action<SPWorkflowAssociation> method)
		{
			if (list == null) return;
			if (method == null) throw new ArgumentNullException("method");

			var associations = list.WorkflowAssociations;

			foreach (SPWorkflowAssociation association in associations)
				method(association);
		}

		/// <summary>
		/// Executes <paramref name="method"/> for each <paramref name="list"/> workflow association, all associations are saved in temporary collection
		/// </summary>
		/// <exception cref="ArgumentNullException"><paramref name="method"/> is null</exception>
		public static void SafeForEachAssociation(this SPList list, Action<SPWorkflowAssociation> method)
		{
			if (list == null) return;
			if (method == null) throw new ArgumentNullException("method");

			var associations = list.WorkflowAssociations.Cast<SPWorkflowAssociation>().ToArray();

			for (int i = 0, iMax = associations.Length; i < iMax; i++)
				method(associations[i]);
		}

		/// <summary>
		/// Set all templates for <paramref name="contentTypeId"/>
		/// </summary>
		public static void BindFormTemplates(this SPList list, SPContentTypeId contentTypeId, string newFormTemplateName, string editFormTemplateName, string displayFormTemplateName)
		{
			try
			{
				foreach (SPContentType ct in list.ContentTypes)
				{
					if (!ct.Id.IsChildOrEqual(contentTypeId))
						continue;

					if (ct.NewFormTemplateName == newFormTemplateName && ct.EditFormTemplateName == editFormTemplateName && ct.DisplayFormTemplateName == displayFormTemplateName)
						return;

					ct.NewFormTemplateName = newFormTemplateName;
					ct.EditFormTemplateName = editFormTemplateName;
					ct.DisplayFormTemplateName = displayFormTemplateName;

					ct.Update(false, false);
				}
			}
			catch (Exception x)
			{
				H.LX("SPListExts.BindFormTemplates", "BindFormTemplates contentTypeId: " + contentTypeId, x);
			}
		}
	}
}
